/*
 *     os-01.c  Copyright (c) 2021. cc01cc. All rights reserved.
 *
 *     This file is part of os-01.
 *
 *     os-01 is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published
 *     by the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     os-01 is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
// 进程同步-“消费者-生产者”问题
#include <stdio.h>
#include <stdlib.h>

#define N 10

int     in          =       0;        //资源存储位置
int     out         =       0;        //资源消费位置
int     buffer[N];                    //缓冲池包含N个缓冲区

typedef struct  SEMPHORE
{
    int value;
}SEMPHORE;

SEMPHORE canConsum;
SEMPHORE canProduce;
SEMPHORE mutex;

void produce();
void consume();
int main()
{
    int i = 0;                      //使用随机函数rand()模仿系统调用
    srand(0);

    canConsum.value = 0;        //可取资源数量
    canProduce.value = N;       //可存缓冲区空间
    mutex.value = 1;            //互斥信号量
    for(i = 0; i < 1000; i++)
    {
        if(rand()%2==0)             //当随机数为偶数时，调用produce()
        {
            produce();
//            printf("canProduce: %d\t canConsum: %d\n\n", canProduce.value, canConsum.value);
            Sleep(20);
        }else
        {
            consume();
//            printf("canProduce: %d\t canConsum: %d\n\n", canProduce.value, canConsum.value);
            Sleep(20);
        }
    }
    return 0;
}
int wait(SEMPHORE semphore);
int signal_define(SEMPHORE semphore);

//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// 生产者生产资源
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

void produce()
{
    canProduce.value = wait(canProduce);
    if(canProduce.value!=-1)   //判断缓冲池是否留有存放资源的空间
    {
        mutex.value = wait(mutex);
        if(mutex.value!=-1)    //判断互斥信号量
        {
            buffer[in] = in;    //向缓冲池传输数据
            printf("Produce: %d\n", buffer[in]);
            in = (in + 1) % N;
            mutex.value = signal_define(mutex);
            canConsum.value = signal_define(canConsum);
        }else
        {
            printf("P: Resource blocked!\n");   //资源堵塞
            canProduce.value++;
        }
    }else
    {
        canProduce.value = 0;
        printf("Buffer pool is full!\n");       //缓冲池已满
    }
}
int wait(SEMPHORE semphore);
int signal_define(SEMPHORE semphore);

//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// 消费者消费资源
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

void consume()
{
    canConsum.value = wait(canConsum);
    if(canConsum.value!=-1)
    {
        mutex.value = wait(mutex);
        if(mutex.value!=-1)
        {
            buffer[out] = -1*out;
            printf("\t\tconsume: %d\n", buffer[out]);
            out = (out + 1)% N;
            mutex.value = signal_define(mutex);
            canProduce.value = signal_define(canProduce);
        }else
        {
            printf("\t\tC: Resource blocked!\n");
            canConsum.value++;
        }
    }else
    {
        canConsum.value = 0;
        printf("\t\tUnusable buffer!\n");   //无可用缓冲区
    }
}

//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// 控制访问，以及减少资源数量
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

int wait(SEMPHORE semphore)
{
    int value = semphore.value;
    if(value > 0)
    {
        value = value - 1;
        return value;
    }else
    {
        return -1;
    }
}

//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// 增加资源数量
// 因与库函数singal()重名，故改名为singal_define();
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

int signal_define(SEMPHORE semphore)
{
    int value = semphore.value;
    return value + 1;
}
